package threadDemo;

import org.apache.log4j.Logger;
import org.junit.Test;

import java.util.concurrent.*;

/**
 * @author zybw-kf01 2018-5-14
 * <p>
 * 子线程完成某件任务后，把得到的结果回传给主线
 * <p>
 * 回顾线程的创建，我们一般会把 Runnable 对象传给 Thread 去执行。
 * <p>
 * Callable 最大区别就是返回范型 V 结果。
 * <p>
 * <p>
 * 可以看到，主线程调用 futureTask.get() 方法时阻塞主线程；然
 * 后 Callable 内部开始执行，并返回运算结果；此时 futureTask.get() 得到结果，主线程恢复运行。
 * <p>
 * 这里我们可以学到，通过 FutureTask 和 Callable 可以直接在主线程获得子线程的运算结果，只不过需要阻塞主线程。
 * 当然，如果不希望阻塞主线程，可以考虑利用 ExecutorService，把 FutureTask 放到线程池去管理执行。
 */
public class Callable01 {

    private static final Logger logger = Logger.getLogger(Callable01.class);

    public static void main(String[] args) throws Exception {
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(2000);
                return "call result a";
            }
        });
        Thread thread = new Thread(task);
        thread.start();
        System.out.println("start");
        Object o = task.get();
        System.out.println("task.get():" + o);


//		futureSubmitRunnable();
//		doTaskWithResultInWorker();

        futureCancle();

    }


		//测试 Cancle
    private static void futureCancle() {
        Future future = Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
									System.out.println("Callable01:run:sleep 之后");
                } catch (InterruptedException e) {
                    System.out.println("catch interrupt --Cancle成功😄");
                    e.printStackTrace();
                }
							System.out.println("Callable01:run:over...try catch 外 over");
            }
        });

        try {
            Thread.sleep(100);
//			等待状态。此时调用cancel()方法不管传入true还是false都会标记为取消，任务依然保存在任务队列中，但当轮到此任务运行时会直接跳过。
//			完成状态。此时cancel()不会起任何作用，因为任务已经完成了。
//			运行中。此时传入true会中断正在执行的任务，传入false则不会中断。
					System.out.println("Callable01:futureCancle: start cancle 😄");
            future.cancel(true);//TODO InterruptedException 执行。
//			future.cancel(false);//没有反应
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

//		try {
//			System.out.println("start blocking");
//			Object o = future.get();
//			System.out.println("get from runnable "+o);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		} catch (ExecutionException e) {
//			e.printStackTrace();
//		}
        System.out.println("调用的方法。 over");
    }

    @Test
    public void futureSubmitRunnable() {
        logger.info("futureSubmitRunnable: ");
        Future future = Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    logger.info("run: start");
                    Thread.sleep(2000);
                    logger.info("run: over");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        while (!future.isDone()) {
            try {
                Thread.sleep(300);
                logger.info("futureSubmitRunnable: not done sleep 300 ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        try {
            System.out.println("start blocking start get()-------->");
            Object o = future.get();
            System.out.println("get from runnable " + o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

		@Test
    public void doTaskWithResultInWorker() {

        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.err.println("Task starts" + Thread.currentThread().getName());
                int result = 0;
                for (int i = 0; i < 101; i++) {
                    result += i;
                }
                Thread.sleep(2000);
                System.err.println("Task finished and return result");
                return result;
            }
        };

			//Task 1
			Future<Integer> submit = Executors.newCachedThreadPool().submit(callable);
        System.out.println("pool submit 11");
        try {
            // TODO: 2019-12-09
            //  为了防止调用 Future.get() 方法阻塞当前线程，
            //  推荐的做法是先调用 Future.isDone() 判断任务是否完成，然后再调用 Future.get() 从完成的任务中获取任务执行的结果。
            boolean done = submit.isDone();
            System.out.println("is done 11 " + done);
            Integer integer = submit.get();
            System.out.println("future get result = " + integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        //Task 2
        FutureTask<Integer> cFutureTask = new FutureTask<>(callable);
        new Thread(cFutureTask).start();
        System.out.println("task start");
        try {
            while (true) {
                boolean done = cFutureTask.isDone();
                Thread.sleep(100);
                System.out.println("is done " + done);
                if (done) {
                    System.out.println("Before futureTask.get()");
                    System.out.println("Result:" + cFutureTask.get());
                    System.out.println("After futureTask.get()");
                    break;
                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}
